
local FruitItem = import("app.views.FruitItem")
local PlayScene = class("PlayScene", function()
    return display.newScene("PlayScene")
end)

function PlayScene:ctor()
    local ud = cc.UserDefault:getInstance()
    print("the save path:", cc.UserDefault:getXMLFilePath())

    self.highSorce = ud:getIntegerForKey("highSorce")
    self.stage = ud:getIntegerForKey("stage")
    if self.stage == 0 then self.stage = 1 end
    self.target = self.stage * 100
    self.curScore = 0

    self.xCount = 8 -- 水平方向水果数
    self.yCount = 8 -- 垂直方向水果数
    self.fruitGap = 0 -- 水果间距

    self.scoreStart = 5 -- 水果基分
    self.scoreStep = 10 -- 加成分数
    self.activeScore = 0 -- 当前高亮的水果得分

    math.newrandomseed()

    -- 1 号水果左下角坐标常量
    local fruitWidth = FruitItem.getWidth()
    self.matrixLBX = (display.width - self.xCount*fruitWidth - (self.xCount-1)*self.fruitGap) / 2
    self.matrixLBY = (display.height - self.yCount*fruitWidth - (self.yCount-1)*self.fruitGap) / 2 - 30

    -- 监听转场效果结束事件
    self:registerScriptHandler(function(event) 
            if event == "enterTransitionFinish" then
                self:initMatrix()
            end
        end)

    self:initUI()

    AudioEngine.playMusic("music/mainbg.mp3", true)
    AudioEngine.setMusicVolume(0.4)
end

function PlayScene:initUI()
    -- 背景图片
    display.newSprite("playBG.png")
        :addTo(self)
        :move(display.cx, display.cy)

    -- high sorce
    display.newSprite("#high_score.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.left + 15, display.top - 30)

    display.newSprite("#highscore_part.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.cx + 10, display.top - 26)

    cc.Label:createWithBMFont("font/earth38.fnt", tostring(self.highSorce))
        :addTo(self)
        :align(display.CENTER, display.cx + 105, display.top - 24)
    
    -- 声音
    display.newSprite("#sound.png")
        :addTo(self)
        :align(display.CENTER, display.right - 60, display.top - 30)

    -- stage
    display.newSprite("#stage.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.left + 15, display.top - 80)

    display.newSprite("#stage_part.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.left + 170, display.top - 80)

    cc.Label:createWithBMFont("font/earth32.fnt", tostring(self.stage))
        :addTo(self)
        :align(display.CENTER, display.left + 214, display.top - 78)
    
    -- target
    display.newSprite("#tarcet.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.cx - 50, display.top - 80)

    display.newSprite("#tarcet_part.png")
        :addTo(self)
        :align(display.LEFT_CENTER, display.cx + 130, display.top - 78)

    cc.Label:createWithBMFont("font/earth32.fnt", tostring(self.target))
        :addTo(self)
        :align(display.CENTER, display.cx + 195, display.top - 76)

    -- current sorce
    display.newSprite("#score_now.png")
        :addTo(self)
        :align(display.CENTER, display.cx, display.top - 150)

    self.curScoreLabel = cc.Label:createWithBMFont("font/earth48.fnt", tostring(self.curScore))
        :addTo(self)
        :align(display.CENTER, display.cx, display.top - 150)

    -- 水果分数
    self.activeScoreLabel = cc.Label:createWithSystemFont("", display.DEFAULT_TTF_FONT, 30)
        :addTo(self)
        :move(display.cx, 120)
        :setTextColor(display.COLOR_WHITE)
        :setLocalZOrder(10) -- 确保不会被 self.sliderBar 挡住

    self.sliderBar = ccui.Slider:create("The_time_axis_Tunnel.png", "The_time_axis_Trolley.png", ccui.TextureResType.plistType)
        :addTo(self)
        :align(display.LEFT_BOTTOM, 0, 0)
        :setContentSize(display.width, 125)
        :setPercent(0)
        :setTouchEnabled(false) -- 不需要事件，仅仅当成进度条
end

function PlayScene:initMatrix()
    self.matrix = {}
    self.actives = {}
    for y = 1, self.yCount do
        for x = 1, self.xCount do
            if x == 2 and y == 1 then
                self:createAndDropFruit(x, y, self.matrix[1].fruitIndex)
            else
                self:createAndDropFruit(x, y)
            end
        end
    end
end

function PlayScene:createAndDropFruit(x, y, fruitIndex)
    local fruit = FruitItem.new(x, y, fruitIndex)
    self:addChild(fruit)

    local pos = self:positionOfFruit(x, y)
    local startPos = cc.p(pos.x, pos.y + display.height / 2)
    fruit:setPosition(startPos)

    local speed = startPos.y / (2*display.height)
    fruit:runAction(cc.MoveTo:create(speed, pos))

    self:setFruit(x, y, fruit)

    local function OnTouchOBOBegan(touch, event)
        return true
    end

    local function OnTouchOBOEnded(touch, event)
        local pos = touch:getLocation()
        if cc.rectContainsPoint(fruit:getBoundingBox(), pos) then
            print("you click fruit", fruit.x, fruit.y, pos.x, pos.y)
            if fruit.isActive then
                -- 消除音效
                local musicIndex = #self.actives
                if musicIndex < 2 then musicIndex = 2 end
                if musicIndex > 9 then musicIndex = 9 end
                AudioEngine.playEffect(string.format("music/broken%d", musicIndex))

                self:removeActivedFruits()
                self:dropFruits()
                self:checkNextStage()
            else
                self:inactive()
                self:activeNeighbor(fruit)
                self:showActivesScore()

                -- 高亮音效
                AudioEngine.playEffect("music/itemSelect.mp3")
            end
        end
    end

    local listener = cc.EventListenerTouchOneByOne:create()
    listener:registerScriptHandler(OnTouchOBOBegan, cc.Handler.EVENT_TOUCH_BEGAN)
    listener:registerScriptHandler(OnTouchOBOEnded, cc.Handler.EVENT_TOUCH_ENDED)
    local eventDispatcher = self:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, fruit)
end

function PlayScene:setFruit(x, y, fruit)
    if x >= 1 and x <= self.xCount and
       y >= 1 and y <= self.yCount then
        self.matrix[(y-1)*self.xCount + x] = fruit
    end
end

function PlayScene:getFruit(x, y)
    if x >= 1 and x <= self.xCount and
       y >= 1 and y <= self.yCount then
        return self.matrix[(y-1)*self.xCount + x]
    end
end

-- 计算水果的坐标，取水果的中心点位置（正方形的中心）。
function PlayScene:positionOfFruit(x, y)
    local fruitWidth = FruitItem.getWidth()
    local px = self.matrixLBX + (fruitWidth + self.fruitGap) * (x - 1) + fruitWidth / 2
    local py = self.matrixLBY + (fruitWidth + self.fruitGap) * (y - 1) + fruitWidth / 2
    return cc.p(px, py)
end

function PlayScene:inactive()
    for _, fruit in ipairs(self.actives) do
        fruit:setActive(false)
    end
    self.actives = {}
end

local function _activeNeighbor(self, fruit, neighbor)
    if neighbor.isActive == false and neighbor.fruitIndex == fruit.fruitIndex then
        neighbor:setActive(true)
        self.actives[#self.actives+1] = neighbor
        self:activeNeighbor(neighbor)
    end
end

function PlayScene:activeNeighbor(fruit)
    if fruit.isActive == false then
        fruit:setActive(true)
        self.actives[#self.actives+1] = fruit
    end

    local neighbor
    local leftx, lefty = fruit.x - 1, fruit.y
    if leftx >= 1 then
        neighbor = self:getFruit(leftx, lefty)
        _activeNeighbor(self, fruit, neighbor)
    end

    local rightx, righty = fruit.x + 1, fruit.y
    if rightx <= self.yCount then
        neighbor = self:getFruit(rightx, righty)
        _activeNeighbor(self, fruit, neighbor)
    end

    local upx, upy = fruit.x, fruit.y + 1
    if upy <= self.yCount then
        neighbor = self:getFruit(upx, upy)
        _activeNeighbor(self, fruit, neighbor)
    end

    local downx, downy = fruit.x, fruit.y - 1
    if downy >= 1 then
        neighbor = self:getFruit(downx, downy)
        _activeNeighbor(self, fruit, neighbor)
    end
end

function PlayScene:showActivesScore()
    local num = #self.actives
    if num == 1 then
        self:inactive()
        self.activeScoreLabel:setString("")
        self.activeScore = 0
        return
    end

    -- 水果分数依次是 5, 15, 25, 35, ... 求这个等差数列的和
    self.activeScore = (self.scoreStart*2 + self.scoreStep*(num-1)) * num / 2
    self.activeScoreLabel:setString(string.format("%d 连消，得分 %d", num, self.activeScore))
end

function PlayScene:removeActivedFruits()
    local fruitScore = self.scoreStart
    for _, fruit in ipairs(self.actives) do
        self:setFruit(fruit.x, fruit.y, nil)
        self:scorePopupEffect(fruitScore, fruit:getPosition())
        fruitScore = fruitScore + self.scoreStep

        -- 爆照特效
        local time = 0.3
        -- 爆照圈
        local circle = display.newSprite("circle.png")
            :move(fruit:getPosition())
            :addTo(self)
            :setScale(0)
        circle:runAction(cc.Sequence:create(
                cc.ScaleTo:create(time, 1.0),
                cc.CallFunc:create(function() circle:removeFromParent() end)
            ))
        -- 爆照碎片
        local emitter = cc.ParticleSystemQuad:create("stars.plist")
            :setAutoRemoveOnFinish(true)
        emitter:move(fruit:getPosition())
        local batch = cc.ParticleBatchNode:createWithTexture(emitter:getTexture())
        batch:addChild(emitter)
        self:addChild(batch)

        fruit:removeFromParent()
    end

    self.actives = {}

    self.curScore = self.curScore + self.activeScore
    self.curScoreLabel:setString(tostring(self.curScore))

    self.activeScoreLabel:setString("")
    self.activeScore = 0

    local percent = self.curScore / self.target * 100
    if percent > 100 then percent = 100 end
    self.sliderBar:setPercent(percent)
end

function PlayScene:scorePopupEffect(score, px, py)
    local label = cc.Label:createWithBMFont("font/earth32.fnt", tostring(score))
        :addTo(self)

    local move = cc.MoveBy:create(0.8, cc.p(0, 80))
    local fadeOut = cc.FadeOut:create(0.8)
    local action = cc.Sequence:create(cc.Spawn:create(move, fadeOut),
                    cc.CallFunc:create(function() label:removeFromParent() end))

    label:move(px, py):runAction(action)
end

function PlayScene:dropFruits()
    local emptyInfo = {}
    for x = 1, self.xCount do
        local removedFruits = 0
        local newy = 0

        for y = 1, self.yCount do
            local fruit = self:getFruit(x, y)
            if fruit == nil then
                removedFruits = removedFruits + 1
            else
                -- 向下补缺空位
                if removedFruits > 0 then
                    newy = y - removedFruits
                    fruit.y = newy
                    self:setFruit(x, newy, fruit)
                    self:setFruit(x, y, nil)

                    local pos = self:positionOfFruit(x, newy)
                    local speed = (fruit:getPositionY() - pos.y) / display.height
                    fruit:stopAllActions()
                    fruit:runAction(cc.MoveTo:create(speed, pos))
                end
            end
        end

        emptyInfo[x] = removedFruits
    end

    for x = 1, self.xCount do
        for y = self.yCount - emptyInfo[x] + 1, self.yCount do
            self:createAndDropFruit(x, y)
        end
    end
end

function PlayScene:checkNextStage()
    if self.curScore < self.target then
        return
    end
    AudioEngine.playEffect("music/wow.mp3")

    -- 创建 layer 显示结果，并拦截事件
    local layer = display.newLayer(cc.c4b(0, 0, 0, 150))
        :addTo(self)

    local function onTouchOBOBegan(touch, event)
        return true
    end

    local listener = cc.EventListenerTouchOneByOne:create()
                :setSwallowTouches(true)
    listener:registerScriptHandler(onTouchOBOBegan, cc.Handler.EVENT_TOUCH_BEGAN)
    local eventDispatcher = self:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)

    if self.curScore > self.highSorce then
        self.highSorce = self.curScore 
    end
    self.stage = self.stage + 1
    self.target = self.stage * 100

    -- 保存数据
    local ud = cc.UserDefault:getInstance()
    ud:setIntegerForKey("highSorce", self.highSorce)
    ud:setIntegerForKey("stage", self.stage)

    local text = string.format("恭喜过关！\n最高得分：%d", self.highSorce)
    self.activeScoreLabel = cc.Label:createWithSystemFont(text, display.DEFAULT_TTF_FONT, 60)
        :addTo(layer)
        :move(display.cx, display.cy + 140)
        :setTextColor(display.COLOR_WHITE)

    ccui.Button:create("startBtn_N.png", "startBtn_S.png", "", ccui.TextureResType.plistType)
        :addTo(layer)
        :move(display.cx, display.cy - 80)
        :addClickEventListener(function(btn)
                AudioEngine.stopMusic()
                cc._app:enterScene("MainScene", "flipX", 0.5)
            end)
end

return PlayScene
